#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
WebSocket客户端
"""

import json
import asyncio
import websockets
from typing import Callable, Optional, Dict, Any
from PyQt6.QtCore import QObject, pyqtSignal, QThread, QTimer
from PyQt6.QtWidgets import QMessageBox


class WebSocketClient(QObject):
    """WebSocket客户端"""
    
    # 信号定义
    connected = pyqtSignal()
    disconnected = pyqtSignal()
    message_received = pyqtSignal(dict)
    error_occurred = pyqtSignal(str)
    
    def __init__(self, server_url: str = "ws://localhost:8000/ws"):
        super().__init__()
        self.server_url = server_url
        self.websocket = None
        self.running = False
        self.reconnect_interval = 5000  # 5秒重连间隔
        self._thread = None  # 用于重连的线程引用
        
    async def connect(self):
        """连接到服务器"""
        try:
            print(f"正在连接到服务器: {self.server_url}")
            self.websocket = await websockets.connect(self.server_url)
            self.running = True
            self.connected.emit()
            print("WebSocket连接成功")
            
            # 开始监听消息
            await self._listen_messages()
            
        except Exception as e:
            error_msg = f"WebSocket连接失败: {str(e)}"
            print(error_msg)
            self.error_occurred.emit(error_msg)
            self._start_reconnect()
    
    async def disconnect(self):
        """断开连接"""
        self.running = False
        
        if self.websocket:
            await self.websocket.close()
            self.websocket = None
        
        self.disconnected.emit()
        print("WebSocket连接已断开")
    
    async def send_message(self, message: Dict[str, Any]):
        """发送消息"""
        if not self.websocket:
            self.error_occurred.emit("WebSocket未连接")
            return False
        
        try:
            message_str = json.dumps(message, ensure_ascii=False)
            await self.websocket.send(message_str)
            print(f"发送消息: {message.get('type', 'unknown')}")
            return True
        except Exception as e:
            error_msg = f"发送消息失败: {str(e)}"
            print(error_msg)
            self.error_occurred.emit(error_msg)
            return False
    
    async def _listen_messages(self):
        """监听消息"""
        try:
            while self.running:
                try:
                    # 使用asyncio.wait_for添加超时
                    message = await asyncio.wait_for(
                        self.websocket.recv(), 
                        timeout=60.0  # 60秒超时
                    )
                    
                    if not message:
                        continue
                    
                    data = json.loads(message)
                    msg_type = data.get('type', 'unknown')
                    print(f"📨 收到消息: {msg_type}")
                    
                    # 根据消息类型打印详细信息
                    if msg_type == 'initial_data':
                        orders = data.get('orders', [])
                        print(f"📊 初始数据: {len(orders)} 个订单")
                        for i, order in enumerate(orders[:3]):  # 只显示前3个
                            print(f"  {i+1}. {order.get('number', '')} - {order.get('customer', '')}")
                        if len(orders) > 3:
                            print(f"  ... 还有 {len(orders) - 3} 个订单")
                    
                    elif msg_type == 'order_status_change':
                        order_data = data.get('data', {})
                        order_number = order_data.get('order_number', '')
                        status = order_data.get('status', {})
                        print(f"🔄 订单状态变化: 编号 {order_number}")
                        print(f"📊 状态数据: {status}")
                    
                    elif msg_type == 'order_created':
                        order = data.get('order', {})
                        print(f"🆕 订单已创建: {order.get('number', '')} - {order.get('customer', '')}")
                    
                    elif msg_type == 'order_updated':
                        order = data.get('order', {})
                        print(f"🔄 订单已更新: {order.get('number', '')} - {order.get('customer', '')}")
                    
                    elif msg_type == 'order_deleted':
                        order_data = data.get('data', {})
                        order_number = order_data.get('order_number', '')
                        order_info = order_data.get('order_info', {})
                        print(f"🗑️ 订单已删除: 编号 {order_number}")
                        print(f"📋 订单信息: {order_info.get('number', '')} - {order_info.get('customer', '')}")
                    
                    elif msg_type == 'monitoring_started':
                        base_path = data.get('base_path', '')
                        date = data.get('date', '')
                        print(f"🔍 监控已开始: {base_path}/{date}")
                    
                    elif msg_type == 'monitoring_stopped':
                        print(f"⏹️ 监控已停止")
                    
                    elif msg_type == 'error':
                        error_msg = data.get('message', '')
                        print(f"❌ 服务端错误: {error_msg}")
                    
                    else:
                        print(f"❓ 未知消息类型: {msg_type}")
                        print(f"📄 消息内容: {data}")
                    
                    self.message_received.emit(data)
                except json.JSONDecodeError as e:
                    print(f"❌ 解析消息失败: {e}")
                    print(f"📄 原始消息: {message}")
                except asyncio.TimeoutError:
                    # 超时，发送ping保持连接
                    print("⏱️ 接收超时，发送心跳")
                    try:
                        await self.websocket.ping()
                        print("✅ 心跳发送成功")
                    except Exception as e:
                        print(f"❌ 心跳发送失败: {e}")
                        break
                except Exception as e:
                    print(f"❌ 处理消息时出错: {e}")
                    
        except websockets.exceptions.ConnectionClosed as e:
            print(f"WebSocket连接被关闭: {e.code} - {e.reason}")
            
            # 1012表示服务重启，需要重连
            if e.code == 1012:
                print("🔄 服务器重启，等待重连...")
            
            self.running = False
            self.disconnected.emit()
            # 连接关闭时也尝试重连
            self._start_reconnect()
        except asyncio.TimeoutError as e:
            error_msg = f"WebSocket超时: {str(e)}"
            print(error_msg)
            self.error_occurred.emit(error_msg)
            self.running = False
            # 超时也尝试重连
            self._start_reconnect()
        except Exception as e:
            error_msg = f"监听消息时发生错误: {str(e)}"
            print(error_msg)
            self.error_occurred.emit(error_msg)
            self.running = False
            # 其他错误也尝试重连
            self._start_reconnect()
        finally:
            # 移除finally中的重连逻辑，避免重复重连
            pass
    
    def _start_reconnect(self):
        """开始重连"""
        print(f"将在{self.reconnect_interval/1000}秒后重连...")
        # 使用QTimer.singleShot避免线程问题
        QTimer.singleShot(self.reconnect_interval, self._reconnect)
    
    def _reconnect(self):
        """重连"""
        print(f"🔄 开始重连...")
        # 在WebSocket线程中重连
        if hasattr(self, '_thread') and self._thread:
            self._thread.start()
    
    def is_connected(self) -> bool:
        """检查是否已连接"""
        return self.websocket is not None and self.running


class WebSocketThread(QThread):
    """WebSocket线程"""
    
    def __init__(self, client: WebSocketClient):
        super().__init__()
        self.client = client
        self.loop = None
    
    def run(self):
        """运行线程"""
        self.loop = asyncio.new_event_loop()
        asyncio.set_event_loop(self.loop)
        
        try:
            self.loop.run_until_complete(self.client.connect())
        except Exception as e:
            print(f"WebSocket线程错误: {e}")
        finally:
            self.loop.close()
    
    def stop(self):
        """停止线程"""
        if self.loop and self.loop.is_running():
            asyncio.run_coroutine_threadsafe(self.client.disconnect(), self.loop)
        
        self.quit()
        self.wait()


# 全局WebSocket管理器实例
_global_websocket_manager = None

def get_websocket_manager(server_url: str = "ws://localhost:8000/ws"):
    """获取全局WebSocket管理器实例"""
    global _global_websocket_manager
    if _global_websocket_manager is None:
        _global_websocket_manager = WebSocketManager(server_url)
    return _global_websocket_manager


class WebSocketManager(QObject):
    """WebSocket管理器 - 提供同步接口，单例模式"""
    
    _instance = None
    _initialized = False
    
    # 信号定义
    connected = pyqtSignal()
    disconnected = pyqtSignal()
    message_received = pyqtSignal(dict)  # 添加通用消息接收信号
    orders_received = pyqtSignal(list)
    order_created = pyqtSignal(dict)
    order_updated = pyqtSignal(dict)
    order_deleted = pyqtSignal(int)
    order_status_changed = pyqtSignal(dict)
    monitoring_started = pyqtSignal(str, str)
    monitoring_stopped = pyqtSignal()
    angle_recognition_completed = pyqtSignal(dict)
    task_statistics_completed = pyqtSignal(dict)
    error_occurred = pyqtSignal(str)
    
    def __new__(cls, server_url: str = "ws://localhost:8000/ws"):
        if cls._instance is None:
            cls._instance = super(WebSocketManager, cls).__new__(cls)
        return cls._instance
    
    def __init__(self, server_url: str = "ws://localhost:8000/ws"):
        # 如果已经初始化，检查是否需要更新URL
        if self._initialized:
            if hasattr(self, 'client') and self.client.server_url != server_url:
                print(f"🔄 更新WebSocket URL: {self.client.server_url} -> {server_url}")
                # 停止当前连接
                if self.thread.isRunning():
                    self.thread.stop()
                # 创建新的客户端和线程
                self.client = WebSocketClient(server_url)
                self.thread = WebSocketThread(self.client)
                self.client._thread = self.thread
                # 重新连接信号
                self.client.connected.connect(self.connected.emit)
                self.client.disconnected.connect(self.disconnected.emit)
                self.client.message_received.connect(self._handle_message)
                self.client.error_occurred.connect(self.error_occurred.emit)
            return
            
        super().__init__()
        self.client = WebSocketClient(server_url)
        self.thread = WebSocketThread(self.client)
        
        # 设置线程引用，用于重连
        self.client._thread = self.thread
        
        # 连接信号
        self.client.connected.connect(self.connected.emit)
        self.client.disconnected.connect(self.disconnected.emit)
        self.client.message_received.connect(self._handle_message)
        self.client.error_occurred.connect(self.error_occurred.emit)
        
        self._initialized = True
    
    @classmethod
    def get_instance(cls, server_url: str = "ws://localhost:8000/ws"):
        """获取WebSocket管理器单例实例"""
        if cls._instance is None:
            cls._instance = cls(server_url)
        return cls._instance
    
    def start(self):
        """启动WebSocket连接"""
        if not self.thread.isRunning():
            self.thread.start()
    
    def stop(self):
        """停止WebSocket连接"""
        self.thread.stop()
    
    def _handle_message(self, message: dict):
        """处理收到的消息"""
        msg_type = message.get('type')
        
        # 发出通用消息接收信号
        self.message_received.emit(message)
        
        if msg_type == 'initial_data':
            orders = message.get('orders', [])
            self.orders_received.emit(orders)
        
        elif msg_type == 'order_created':
            order = message.get('order', {})
            self.order_created.emit(order)
        
        elif msg_type == 'order_updated':
            data = message.get('data', {})
            order_info = data.get('order_info', {})
            order_number = data.get('order_number', '')
            print(f"🔄 收到订单更新消息: 编号 {order_number}")
            if order_info:
                self.order_updated.emit(order_info)
            else:
                print(f"⚠️ 订单更新消息缺少信息: {data}")
        
        elif msg_type == 'order_deleted':
            data = message.get('data', {})
            order_number = data.get('order_number', '')
            order_info = data.get('order_info', {})
            print(f"🗑️ 收到订单删除消息: 编号 {order_number}")
            print(f"📋 订单信息: {order_info}")
            if order_number:
                self.order_deleted.emit(order_number)
            else:
                print(f"⚠️ 订单删除消息缺少编号: {data}")
        
        elif msg_type == 'order_status_change':
            data = message.get('data', {})
            print(f"📊 收到状态变化数据: {data}")
            self.order_status_changed.emit(data)
        
        elif msg_type == 'monitoring_started':
            base_path = message.get('base_path', '')
            date = message.get('date', '')
            self.monitoring_started.emit(base_path, date)
        
        elif msg_type == 'monitoring_stopped':
            self.monitoring_stopped.emit()
        
        elif msg_type == 'angle_recognition_completed':
            result = message.get('result', {})
            self.angle_recognition_completed.emit(result)
        
        elif msg_type == 'task_statistics_completed':
            result = message.get('result', {})
            self.task_statistics_completed.emit(result)
        
        elif msg_type == 'error':
            error_msg = message.get('message', '未知错误')
            self.error_occurred.emit(error_msg)
    
    def send_message(self, message: dict):
        """发送消息（异步）"""
        if self.client.websocket:
            asyncio.run_coroutine_threadsafe(
                self.client.send_message(message), 
                self.thread.loop
            )
    
    def get_orders(self):
        """获取所有订单"""
        self.send_message({'type': 'get_orders'})
    
    def create_order(self, order_data: dict):
        """创建订单"""
        self.send_message({
            'type': 'create_order',
            'data': order_data
        })
    
    def update_order(self, order_data: dict):
        """更新订单"""
        self.send_message({
            'type': 'update_order',
            'data': order_data
        })
    
    def delete_order(self, order_number: str):
        """删除订单"""
        self.send_message({
            'type': 'delete_order',
            'order_number': order_number
        })
    
    def start_monitoring(self, base_path: str = "", date: str = ""):
        """开始监控（服务端使用固定路径）"""
        self.send_message({
            'type': 'start_monitoring',
            'data': {
                'base_path': base_path,
                'date': date
            }
        })
    
    def ping(self):
        """发送心跳"""
        self.send_message({'type': 'ping'})
    
    def is_connected(self) -> bool:
        """检查连接状态"""
        return self.client.is_connected()
